/** 
 *  @file
 *  @brief   MASS1 单元 和 MASS2 单元
 *  @author  LiuXing
 *  @date    2025.07.22
 *  @version v1.0
 *  @par Copyright(c):  ShenGong  Simulation corporation
 */

#include "MASSiCalculator.h"
#include "DBManager/IService/Input/Node/INodeService.h"
#include "DBManager/IService/Input/Element/IElementService.h"
#include "DBManager/IService/Input/Property/IPMASSService.h"
#include "SGFem/Pre/Assembly/Assembly.h"

using SG::Algebra::Matrixd;
using SG::DataStructure::Common::Status;
using namespace SG::DataStructure::FEM;
using namespace SG::DBManager;
using SG::FEMSolver::Element::MASSiCalculator;


void MASSiCalculator::Initialize (SG::DataStructure::FEM::ElementTypes type)
{
    m_type = type;
}

namespace
{
    auto GetMASSElement = [](const DBServiceFactorySP& dbServiceFactory, const ElementTypes& type, const std::size_t iEle, CMASS2Data& _OUT massData) -> Status
    {
        if (ElementTypes::ELETYPE_MASS1 == type)
        {
            //此时单元类型为CMASS1（有属性的MASS单元） 
            //读取词条
            CMASS1Data tempMass;
            if (Status::STATUS_Failure == dbServiceFactory->get<IElementService> ()->FindByIndex (iEle, _OUT tempMass))
            {
                // todo: 错误日志
                return Status::STATUS_Failure;
            };
            // 读取属性信息
            PMASSData tempPMass;
            if (Status::STATUS_Failure == dbServiceFactory->get<IPMASSService> ()->FindById (tempMass.m_pId, _OUT tempPMass))
            {
                // todo: 错误日志
                return Status::STATUS_Failure;
            }
            massData.m_id   = tempMass.m_id;
            massData.m_M    = tempPMass.m_M;
            massData.m_g[0] = tempMass.m_g[0];
            massData.m_g[1] = tempMass.m_g[1];
            massData.m_C1   = tempMass.m_C1;
            massData.m_C2   = tempMass.m_C2;
        }
        else
        {
            // 此时单元为CMass2, 直接写入massData即可
            if(Status::STATUS_Failure == dbServiceFactory->get<IElementService>()->FindByIndex (iEle, _OUT massData))
            {
                // todo:错误日志
                return Status::STATUS_Failure;
            }
        }

        return Status::STATUS_Success;
    };
}

void MASSiCalculator::ComputeMass (const SG::DataStructure::Common::Real m, _OUT SG::Algebra::Matrixd& mm)
{
    mm = Matrixd (2, 2, {m, -m, -m, m});
}

void MASSiCalculator::ComputeElementMatries (const SG::DBManager::DBServiceFactorySP dbServiceFactory)
{
    auto& assembly = AssemblyEigen::GetInstance ();

    CMASS2Data element;
    std::vector<std::size_t> nodeIndexSet (2);
    std::vector<int> dofGlobalIndexSet (2);
    std::vector<int> singleDofGlobalIndex(1);  // 接地时的自由度索引（1个）
    Matrixd mm(2, 2);
    Matrixd mmSingle(1, 1);                    // 接地时的质量矩阵（1x1）

    const auto eleSize = dbServiceFactory->get<IElementService>()->GetElementSize (m_type);
    const auto& nodeService = dbServiceFactory->get<INodeService> ();

    //获取 Basic 坐标系下重力加速度
    NodeData node1;
    NodeData node2;

    for (std::size_t iEle{0}; iEle < eleSize; ++iEle)
    {
        // 根据不同类型，获取单元数据
        if (Status::STATUS_Failure == GetMASSElement(dbServiceFactory, m_type, iEle, _OUT element))
        {
            // todo: 错误日志
            continue;
        }

        // 计算单元质量矩阵
        ComputeMass (element.m_M, _OUT mm);

        if (element.m_g[1] > 0)
        {
            //非接地， 获取两个节点的索引
            assembly.FindNodeIndex(element.m_g, _OUT nodeIndexSet);
            // 获取两个节点的全局自由度索引
            assembly.GetGlobalDOFId(nodeIndexSet[0], element.GetDOF1(), _OUT dofGlobalIndexSet[0]);
            assembly.GetGlobalDOFId(nodeIndexSet[1], element.GetDOF2(), _OUT dofGlobalIndexSet[1]);
            // 获取两个节点的详细数据
            if (Status::STATUS_Failure == nodeService->FindByIndex(nodeIndexSet[0], _OUT node1) ||
                Status::STATUS_Failure == nodeService->FindByIndex(nodeIndexSet[1], _OUT node2))
            {
                // todo: 错误日志
                continue;
            }
            // 组装质量矩阵
            assembly.AccumulateCoupledMass(dofGlobalIndexSet, mm);
        }
        else
        {
            //接地
            // 获取第一个节点的索引（忽略第二个节点）
            assembly.FindNodeIndex(element.m_g[0], _OUT nodeIndexSet[0]);
            // 获取第一个节点的全局自由度索引（仅1个自由度）
            assembly.GetGlobalDOFId(nodeIndexSet[0], element.GetDOF1(), _OUT singleDofGlobalIndex[0]);
            // 获取第一个节点的详细数据
            if (Status::STATUS_Failure == nodeService->FindByIndex(nodeIndexSet[0], _OUT node1))
            {
                // todo: 错误日志
                continue;
            }

            // 计算并组装质量矩阵
            mmSingle(0, 0) = mm(0, 0);
            assembly.AccumulateCoupledMass(singleDofGlobalIndex, mmSingle);
        }
    }
}